import 'dart:math';
import 'dart:typed_data';

class Utils {
  // 将 Uint8List 转换为文本
  static String uint8List2Text(Uint8List uint8List) {
    try {
      // Only remove null bytes, not all '0' characters
      return String.fromCharCodes(uint8List).replaceAll('\u0000', '').trim();
    } catch (e) {
      // Fallback to hex string conversion if UTF-8 decoding fails
      return hexString2Text(uint8ListToHexString(uint8List));
    }
  }

  // 将字符串转文本
  static String hexString2Text(String hexString) {
    // 去除可能的空白字符
    hexString = hexString.replaceAll(RegExp(r'\s'), '');

    // 将字符串分割为每两个字符一组
    List<String> hexPairs = [];
    for (int i = 0; i < hexString.length; i += 2) {
      hexPairs.add(hexString.substring(i, i + 2));
    }

    // 将每对十六进制字符转换为 ASCII 字符
    String result = '';
    for (String hexPair in hexPairs) {
      int charCode = int.parse(hexPair, radix: 16);
      if (charCode == 0) break; // 忽略空字符
      result += String.fromCharCode(charCode);
    }

    return result;
  }

  // 奇偶校验算法
  static Uint8List calculateEvenParity(Uint8List data,
      [int offset = 0, int length = 0]) {
    if (length == 0) length = data.length;
    int result = 0;
    for (int i = offset, max = offset + length; i < max; i++) {
      result ^= data[i];
    }
    Uint8List check = Uint8List(1);
    check[0] = result;
    return check;
  }

  // 校验和算法 - 低8位
  static Uint8List calculateCheckSum(Uint8List data,
      [int offset = 0, int length = 0]) {
    if (length == 0) length = data.length;
    int result = 0;
    for (int i = offset, max = offset + length; i < max; i++) {
      result += data[i];
    }
    // 校验和取低8位
    return Utils.int2Uint8List(result & 0xFF).isEmpty
        ? Uint8List(1)
        : Utils.int2Uint8List(result & 0xFF);
  }

  // CRC16_MODBUS标准计算
  static int calculatecrc16(List<int> data) {
    int crc = 0xFFFF; // 初始值
    for (int byte in data) {
      crc ^= byte & 0xFF; // XOR 字节
      for (int i = 0; i < 8; i++) {
        if ((crc & 0x0001) != 0) {
          crc = (crc >> 1) ^ 0xA001; // 右移并异或多项式
        } else {
          crc = crc >> 1;
        }
      }
    }
    var byteData = ByteData(2);
    byteData.setUint16(0, crc & 0xFFFF, Endian.big);
    return crc & 0xFFFF; // 返回 16 位结果
  }

  // 生成区间随机数（包min、max）
  static int random(int min, int max) {
    var result = min + Random().nextInt(max + 1 - min);
    return result;
  }

  // 比较两个 Uint8List 是否相等
  static bool equalUint8Lists(Uint8List list1, Uint8List list2) {
    if (list1.length != list2.length) return false;
    for (int i = 0, length = list1.length; i < length; i++) {
      if (list1[i] != list2[i]) return false;
    }
    return true;
  }

  // uint8List 转换为十六进制字符串
  static String uint8ListToHexString(Uint8List? data) {
    return data == null
        ? ""
        : data.map((byte) => byte.toRadixString(16).padLeft(2, '0')).join('');
  }

  // 十六进制字符串 转换为 Uint8List
  static Uint8List hexStringToUint8List(String hexString) {
    // 移除可能存在的空格和前缀（如 "0x"）
    hexString = hexString.replaceAll(" ", "").replaceAll("0x", "");

    // 确保字符串长度为偶数
    if (hexString.length % 2 != 0) {
      throw const FormatException("Invalid hex string length");
    }

    // 创建一个 Uint8List 来存储结果
    Uint8List result = Uint8List(hexString.length ~/ 2);

    // 遍历字符串，每两个字符转换为一个字节
    for (int i = 0; i < hexString.length; i += 2) {
      String hexByte = hexString.substring(i, i + 2);
      int byte = int.parse(hexByte, radix: 16);
      result[i ~/ 2] = byte;
    }

    return result;
  }

  // Tab 长度 0-4 字节，高位在前，每个字节的低 7 位 bit[6:0]表示具体数值，最高位 bit7 表示其后是否还有 Tab 字节，
  // bit7 为 1 表示其后一个字节依然属于 Tab，0 表示本字节已是最后一个 Tab 字节
  // Tab 编码
  static Uint8List encodeTab(int value) {
    int length = 0;
    if (value <= 0x7F) {
      length = 1;
    } else if (value <= 0x3FFF) {
      length = 2;
    } else if (value <= 0x1FFFFF) {
      length = 3;
    } else if (value < 0xFFFFFFF) {
      length = 4;
    } else {
      throw ArgumentError('Value must be between 0 and 0xFFFFFFF');
    }
    Uint8List bytes = Uint8List(length);

    for (int i = 0; i < length; i++) {
      int v = (value >> (7 * (length - i - 1)) | 0x80);
      if (v > 0xFF) {
        v = v & 0xFF;
      }
      bytes[i] = v;
    }
    bytes[length - 1] = (bytes[length - 1] ^ 0x80);
    return bytes;
  }

  // Tab解码
  static int decodeTab2Tnt(Uint8List bytes) {
    if (bytes.isEmpty) {
      throw ArgumentError('Bytes list cannot be empty');
    }

    int tab = 0;
    for (int i = 0; i < bytes.length; i++) {
      int b = bytes[i];
      int chunk = b & 0x7F;
      tab = (tab << 7) | chunk;
      // bit7 == 0 表示最后一个字节
      if ((b & 0x80) == 0) {
        break;
      }
    }
    return tab;
  }

  // Tab解码
  static Uint8List decodeTab2Uint8List(Uint8List bytes) {
    return encodeTab(decodeTab2Tnt(bytes));
  }

  // 构建cmd
  static Uint8List encodeCmd(
    int value, {
    required bool isRsp,
    required bool isWrite,
  }) {
    if (value < 0 || value > 0x3FFFFFF) {
      throw ArgumentError('Value must be between 0 and 0x3FFFFFF');
    }

    int byteLength = 0;
    if (value <= 0x1F) {
      byteLength = 1;
    } else if (value <= 0xFFF) {
      byteLength = 2;
    } else if (value <= 0x7FFFF) {
      byteLength = 3;
    } else if (value <= 0x3FFFFFF) {
      byteLength = 4;
    }

    var buffer = ByteData(byteLength);
    switch (byteLength) {
      case 1:
        buffer.setUint8(0, value);
        break;
      case 2:
        buffer.setUint16(0, value, Endian.big);
        break;
      case 3:
        buffer.setUint8(0, (value >> 16) & 0xFF);
        buffer.setUint8(1, (value >> 8) & 0xFF);
        buffer.setUint8(2, value & 0xFF);
        break;
      case 4:
        buffer.setUint32(0, value, Endian.big);
        break;
    }

    Uint8List bytes = buffer.buffer.asUint8List();

    if (byteLength > 1) {
      // 设置 bit5
      bytes[0] |= 0x20;
      for (int i = 1; i < byteLength; i++) {
        // 设置 bit7
        if (i < byteLength - 1) {
          bytes[i] |= 0x80;
        }
      }
    }

    // 配置 bit6 和 bit7
    if (isWrite) {
      bytes[0] |= 0x40; // 设置 bit6
    }
    if (isRsp) {
      bytes[0] |= 0x80; // 设置 bit7
    }

    return bytes;
  }

  // 根据Uint8List 提取 cmd
  static (int, int) decodeCmd(Uint8List result) {
    if (result.isEmpty) {
      throw ArgumentError("Result cannot be empty");
    }

    int cmd = 0;
    int shift = 0;
    int cmdLength = 1; // 记录扩展的字节数

    // 解析第一个字节
    int byte = result[0];
    cmd |= (byte & 0x1F); // 低5位
    shift = 5;

    // 检查是否需要扩展
    if ((byte & 0x20) != 0) {
      // 检查bit5
      for (int i = 1; i < result.length && i <= 3; i++) {
        byte = result[i];
        cmd |= (byte & 0x7F) << shift; // 低7位
        shift += 7;
        cmdLength++; // 每扩展一个字节，计数器加1

        // 如果bit7为0，则结束扩展
        if ((byte & 0x80) == 0) {
          break;
        }
      }
    }
    return (cmd, cmdLength);
  }

  // 计算dataInt
  static int computeDataIntVal(Uint8List msgData) {
    var val = 0;
    for (var i = 0; i < msgData.length; i++) {
      val += msgData[i];
    }
    return val;
  }

  // int 转换为 Uint8List
  static Uint8List int2Uint8List(int number, {Endian endian = Endian.big}) {
    // 计算需要的字节数
    int byteCount = (number.bitLength + 7) ~/ 8;

    // 创建 ByteData
    ByteData byteData = ByteData(byteCount);

    // 将整数写入 ByteData
    for (int i = 0; i < byteCount; i++) {
      int offset = (byteCount - 1 - i) * 8; // 大端序
      byteData.setUint8(i, (number >> offset) & 0xFF);
    }

    // 转换为 Uint8List
    return byteData.buffer.asUint8List();
  }

  // 将 int 转换为 2 字节的 Uint8List
  static Uint8List intTo2Bytes(int value, {Endian endian = Endian.big}) {
    int val = value.clamp(-32768, 32767);
    // 创建一个2字节的缓冲区（16位）
    final ByteData byteData = ByteData(2);
    byteData.setUint16(0, val, endian); // 小端序（可改为 Endian.big）
    return byteData.buffer.asUint8List(); // 转换为字节数组
  }

  // 将 int 转换为 8 字节的 Uint8List
  static Uint8List intTo8Bytes(int value) {
    // 创建一个 8 字节的 ByteData
    final data = ByteData(8);
    // 将 int 写入 ByteData（64 位，8 字节）
    data.setInt64(0, value, Endian.big); // 大端序（网络序）
    // 或使用小端序：
    // data.setInt64(0, value, Endian.big);
    return data.buffer.asUint8List();
  }

  // 将 Uint8List 取出最后 n 个字节，安全处理
  static Uint8List takeLastBytesSafe(Uint8List? data, int n) {
    if (data == null || n <= 0) return Uint8List(0);
    return data.sublist(data.length - n.clamp(0, data.length));
  }

  // 每遇到一个 0xAA 或 0xA5 则在其前方插入一个 0xA5，前两个字节除外
  static List<int> insertBeforTargets(
    List<int> input, {
    List<int> targets = const [0xAA, 0xA5],
    int insert = 0xA5,
    int startIndex = 2, // 从第几个字节开始插入
  }) {
    // 创建一个新的列表来存储处理后的字节
    List<int> output = [];
    // 遍历输入字节数组
    for (int i = 0; i < input.length; i++) {
      // 前两个字节直接添加到输出列表
      if (i < startIndex) {
        output.add(input[i]);
      } else {
        // 检查当前字节是否为 0xAA 或 0xA5
        if (targets.contains(input[i])) {
          // 在 0xAA 或 0xA5 前插入 0xA5
          output.add(insert);
        }
        // 添加当前字节到输出列表
        output.add(input[i]);
      }
    }
    return output;
  }

  // 如果发现某个字节是 insert（默认为 0xA5），并且它后面的字节是 targets 列表中的目标字节之一（默认为 [0xAA, 0xA5]），则移除这个 insert 字节。
  static List<int> removeInsertedBytes(
    List<int> input, {
    List<int> targets = const [0xAA, 0xA5],
    int insert = 0xA5,
    int startIndex = 2, // 从第几个字节开始检查
  }) {
    // 创建一个新的列表来存储处理后的字节
    List<int> output = [];
    // 遍历输入字节数组
    for (int i = 0; i < input.length; i++) {
      // 前 startIndex 个字节直接添加到输出列表
      if (i < startIndex) {
        output.add(input[i]);
      } else {
        // 检查当前字节是否为 insert，且下一个字节是 targets 中的一个
        if (input[i] == insert &&
            i + 1 < input.length &&
            targets.contains(input[i + 1])) {
          // 跳过当前字节（即不添加到 output 中）
          continue;
        }
        // 添加当前字节到输出列表
        output.add(input[i]);
      }
    }
    return output;
  }

  // 将 DateTime 转换为 4 字节的 Uint8List
  static Uint8List dateTimeToBytes(DateTime time) {
    // 验证数据范围
    final year = time.year;
    if (year < 2020 || year > 2084) {
      throw ArgumentError('年份必须在 2020-2084 范围内');
    }

    final month = time.month;
    if (month < 1 || month > 12) {
      throw ArgumentError('月份必须在 1-12 范围内');
    }

    final day = time.day;
    if (day < 1 || day > 31) {
      throw ArgumentError('日期必须在 1-31 范围内');
    }

    final hour = time.hour;
    if (hour < 0 || hour > 23) {
      throw ArgumentError('小时必须在 0-23 范围内');
    }

    final minute = time.minute;
    if (minute < 0 || minute > 59) {
      throw ArgumentError('分钟必须在 0-59 范围内');
    }

    final second = time.second;
    if (second < 0 || second > 59) {
      throw ArgumentError('秒必须在 0-59 范围内');
    }

    // 将各个字段按位组合到 32 位整数中
    int packed = 0;

    // 位域分配：
    // bits 0-5:   second (6 bits, 0-59)
    // bits 6-11:  minute (6 bits, 0-59)
    // bits 12-16: hour   (5 bits, 0-23)
    // bits 17-21: day    (5 bits, 1-31)
    // bits 22-25: month  (4 bits, 1-12)
    // bits 26-31: year   (6 bits, 2020-2084, 存储为 year-2020)

    packed |= (second & 0x3F); // 6 bits for second
    packed |= (minute & 0x3F) << 6; // 6 bits for minute
    packed |= (hour & 0x1F) << 12; // 5 bits for hour
    packed |= (day & 0x1F) << 17; // 5 bits for day
    packed |= (month & 0x0F) << 22; // 4 bits for month
    packed |=
        ((year - 2020) & 0x3F) << 26; // 6 bits for year (offset from 2020)

    // 将 32 位整数转换为 4 字节的 Uint8List
    final bytes = Uint8List(4);
    bytes[0] = packed & 0xFF;
    bytes[1] = (packed >> 8) & 0xFF;
    bytes[2] = (packed >> 16) & 0xFF;
    bytes[3] = (packed >> 24) & 0xFF;

    return bytes;
  }

  // 将 4 字节的 Uint8List 转换为 DateTime
  DateTime bytesToDateTime(Uint8List bytes) {
    if (bytes.length != 4) {
      throw ArgumentError('字节数组长度必须为 4');
    }

    // 将 4 字节重组为 32 位整数
    final packed =
        bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24);

    // 从打包的数据中提取各个字段
    final second = packed & 0x3F;
    final minute = (packed >> 6) & 0x3F;
    final hour = (packed >> 12) & 0x1F;
    final day = (packed >> 17) & 0x1F;
    final month = (packed >> 22) & 0x0F;
    final year = ((packed >> 26) & 0x3F) + 2020;

    return DateTime(year, month, day, hour, minute, second);
  }
}
